package com.airwallex.util;

import com.airwallex.strategy.util.CalculatorContext;
import com.airwallex.model.ExpParam;
import com.airwallex.strategy.CalculateStrategy;
import com.airwallex.strategy.util.CalculateStrategyFactory;
import com.airwallex.util.exception.InsufficientParamException;
import org.apache.commons.lang3.StringUtils;


import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 运算器
 */
public class RPNCalculator {

    // 记录当前可以操作的数的栈
    private Stack<ExpParam> numbers = new Stack<ExpParam>();
    // 记录栈数据的操作日志
    private Stack<List<ExpParam>> logs = new Stack<>();

    //计算表达式
    public void calcRPN(String expression){
        List<ExpParam> expParamList = convertToParamList(expression);
        CalculatorContext context = new CalculatorContext();
        for (ExpParam expParam : expParamList) {
            String paramCnt = expParam.getContent();
            if (expParam.getIsNumber()) {
                numbers.push(expParam);
                CalculatorUtils.addLog(numbers, logs);
                continue;
            }

            CalculateStrategy calculateStrategy = CalculateStrategyFactory.getCalculateStrategy(paramCnt);
            if (calculateStrategy == null) {
                System.out.println("the entered operator【" + paramCnt + "】 Unrecognized !");
                break;
            }

            //设置运算策略
            context.setCalculateStrategy(calculateStrategy);
            //执行具体运算或操作
            try {
                context.execCalc(numbers, logs);
            } catch (InsufficientParamException e) {
                System.out.println("operator " + expParam.getContent()
                        + " (position: "+ expParam.getPos()+"): insucient parameters");
                break;
            }

        }
        CalculatorUtils.printStack(numbers);
    }


    //表达式转换
    private List<ExpParam> convertToParamList(String expression) {
        List<ExpParam> paramList = new ArrayList<>();
        if (StringUtils.isNotBlank(expression)) {
            String[] params = expression.split(" ");
            for (int i = 0; i < params.length; i++) {
                ExpParam paramChar;
                String content = params[i];
                //建造者
                ExpParam.ExpParamBuilder expParamBuilder;
                expParamBuilder = ExpParam.builder().content(content).pos(2*i + 1);
                if (isNumber(content)) {
                    expParamBuilder.num(new BigDecimal(content)).isNumber(true);
                } else {
                    expParamBuilder.isNumber(false);
                }
                paramChar = expParamBuilder.build();
                paramList.add(paramChar);
            }
        }

        return paramList;
    }

    //判断是否是数字
    private boolean isNumber(String str) {
        try {
            BigDecimal b = new BigDecimal(str);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

}
